<template>
  <div id="renderBody" class="relative !overflow-auto" :style="computedStyle">
    <div class="loader" v-if="loading"></div>
    <div
      v-else
      v-for="item in state.layouts"
      :key="item.id"
      class="absolute"
      :class="[item.animationClass]"
      :style="{
        width: item.width + 'px',
        height: item.height + 'px',
        top: item.y + 'px',
        left: item.x + 'px',
      }"
    >
      <component
        :key="item.id"
        :is="item.componentName"
        :width="item.width + 'px'"
        :height="item.height + 'px'"
        :data-id="item.id"
        :id="item.id"
        :iconName="item.iconName"
        :imgName="item.imgName"
        v-model:models="item.props"
        v-model:responseData="item.responseData"
        :themeColor="state.configsJson.themeColor"
        v-on="useEventsBinding(item).baseEvent"
        v-on:vue:mounted="useEventsBinding(item).lifeEvents['vue:mounted']"
        v-on:vue:BeforeMount="
          useEventsBinding(item).lifeEvents['vue:BeforeMount']
        "
      ></component>
    </div>
  </div>
</template>

<script setup lang="ts">
import autofit from "autofit.js";
import { deepClone } from "@renderer/utils/other";
import {
  useEventsBinding,
  generateFilterFunc,
} from "@renderer/hooks/useEvents";
import { useEventHandle } from "@renderer/utils/componentEvent";
const { queryHandler } = useEventHandle();
import Serves from "@renderer/utils/requestNew";
import { useDataSource } from "@renderer/hooks/useDataSource";
import { getTemplateDetail } from "@renderer/api/projectMenu";
import { getDetail } from "@renderer/api/publishMenu";
import {
  onMounted,
  ref,
  reactive,
  inject,
  onBeforeUnmount,
  computed,
  nextTick,
} from "vue";
import { useRouter, useRoute } from "vue-router";
let loading = ref(false);
const route = useRoute();
import { handelResponseData } from "@renderer/utils/handleResponseData";
import { getDataSourceDetail } from "@renderer/api/dataSource";
const { ipcRenderer } = window;
let state: any = reactive({
  layouts: [],
  configsJson: {
    backgroundColor: "#000",
  },
});
let ifFullScreen = ref(false);
let timePolling = reactive({});
const { setShowTitleBar } = inject("titleBar") as any;
onMounted(async () => {
  let type = route.query.type;
  loading.value = true;
  let res: any = null;
  if (type == "template") {
    res = await getTemplateDetail(route.query.id);
  } else {
    res = await getDetail(route.query.id);
  }
  state.layouts = JSON.parse(res.data.detail.layoutJson);
  state.configsJson = JSON.parse(res.data.detail.configJson);
  loading.value = false;
  setNormalHandle();
  setEventQueryHandle();

  nextTick(() => {
    autofit.init({
      dh: state.configsJson.height,
      dw: state.configsJson.width,
      el: "#renderBody",
      resize: true,
    });
  });
  ipcRenderer.send("setFullScreen", ifFullScreen.value);
  document.addEventListener("keydown", function (event) {
    // console.log("event.keyCode", event.keyCode);
    let code = event.keyCode;
    if (code == 122) {
      setShowTitleBar(ifFullScreen.value);
      ifFullScreen.value = !ifFullScreen.value;
      ipcRenderer.send("setFullScreen", ifFullScreen.value);
    } else if (code == 27) {
      setShowTitleBar(true);
      ifFullScreen.value = false;
      ipcRenderer.send("setFullScreen", false);
    }
  });
});

// 事件交互 event 绑定
const setEventQueryHandle = () => {
  let reqList = state.layouts.filter(
    (it) => it.props.control && it.props.event.targetComponent.length > 0
  );

  let targetList = [];
  targetList = reqList
    .map((it) => it.props.event.targetComponent)
    .flat(Infinity);
  // console.log("targetList", targetList);
  targetList.forEach((item) => {
    queryHandler(
      item.targetComponentId,
      item.currentId,
      async (fieldsValue) => {
        let currentIndex = state.layouts.findIndex(
          (it) => it.id == item.targetComponentId
        );

        let obj: any = {};
        // 判断是否使用数据源
        if (state.layouts[currentIndex].ifDataSource) {
          let real_Info: any = await getDataSourceDetail({
            id: state.layouts[currentIndex].dataSourceId,
          });
          if (real_Info.code == 200) {
            state.layouts[currentIndex].dataSourceInfo = real_Info.data;
          } else {
            ElMessage.error("数据源信息获取失败");
            return;
          }
          obj = await useDataSource(
            state.layouts[currentIndex].dataSourceInfo,
            JSON.parse(JSON.stringify(state.layouts[currentIndex].request))
          );
        } else {
          obj = JSON.parse(JSON.stringify(state.layouts[currentIndex].request));
        }

        let fieldsKeys = Object.keys(fieldsValue);
        let paramsKeys = Object.keys(item.targetComponentParams);
        let dataKeys = Object.keys(item.targetComponentData);

        paramsKeys.forEach((key) => {
          if (
            item.targetComponentParams[key] &&
            fieldsKeys.includes(item.targetComponentParams[key])
          ) {
            obj.params[key] = fieldsValue[item.targetComponentParams[key]];
          }
        });

        dataKeys.forEach((key) => {
          if (
            item.targetComponentData[key] &&
            fieldsKeys.includes(item.targetComponentData[key])
          ) {
            obj.data[key] = fieldsValue[item.targetComponentData[key]];
          }
        });

        try {
          let request = new Serves(obj.baseUrl).instance;
          if (obj.ifFormData) {
            let formdata = new FormData();
            for (let key in obj.data) {
              formdata.append(key, obj.data[key]);
            }
            obj.data = formdata;
          }
          const res = await request({
            ...obj,
          });
          const { data } = res;
          let filtedData = generateFilterFunc(
            state.layouts[currentIndex].eventMethods.filterMethod,
            data || {},
            res
          )();
          state.layouts[currentIndex].responseData = filtedData;

          state.layouts[currentIndex].props = handelResponseData(
            state.layouts[currentIndex].responseData,
            state.layouts[currentIndex]
          );
        } catch (error) {
          ElMessage.error(error);
        }
      }
    );
  });
};

// 初始化接口、定时器轮询接口绑定
const setNormalHandle = () => {
  state.layouts.forEach(async (item: any) => {
    if (item.request.ifPolling && item.canReq) {
      if (item.request.ifInit) {
        try {
          let obj: any = {};
          // 判断是否使用数据源
          if (item.ifDataSource) {
            let real_Info: any = await getDataSourceDetail({
              id: item.dataSourceId,
            });
            if (real_Info.code == 200) {
              item.dataSourceInfo = real_Info.data;
              // console.log("item.dataSourceInfo ", item.dataSourceInfo);
            } else {
              ElMessage.error("数据源信息获取失败");
              return;
            }

            obj = await useDataSource(
              item.dataSourceInfo,
              JSON.parse(JSON.stringify(item.request))
            );
          } else {
            obj = JSON.parse(JSON.stringify(item.request));
          }
          let request = new Serves(obj.baseUrl).instance;
          if (obj.ifFormData) {
            let formdata = new FormData();
            for (let key in obj.data) {
              formdata.append(key, obj.data[key]);
            }
            obj.data = formdata;
          }
          const res = await request({
            ...obj,
          });
          const { data } = res;
          let filtedData = generateFilterFunc(
            item.eventMethods.filterMethod,
            data || {},
            res
          )();
          item.responseData = filtedData;
          item.props = handelResponseData(item.responseData, item);
        } catch (error) {
          ElMessage.error("接口数据获取失败：" + error);
        }
      }
      timePolling[item.componentName + item.id] = setInterval(async () => {
        let obj: any = {};
        // 判断是否使用数据源
        if (item.ifDataSource) {
          let real_Info: any = await getDataSourceDetail({
            id: item.dataSourceId,
          });
          if (real_Info.code == 200) {
            item.dataSourceInfo = real_Info.data;
            // console.log("item.dataSourceInfo ", item.dataSourceInfo);
          } else {
            ElMessage.error("数据源信息获取失败");
            return;
          }

          obj = await useDataSource(
            item.dataSourceInfo,
            JSON.parse(JSON.stringify(item.request))
          );
        } else {
          obj = JSON.parse(JSON.stringify(item.request));
        }
        try {
          let request = new Serves(obj.baseUrl).instance;
          if (obj.ifFormData) {
            let formdata = new FormData();
            for (let key in obj.data) {
              formdata.append(key, obj.data[key]);
            }
            obj.data = formdata;
          }
          const res = await request({
            ...obj,
          });
          const { data } = res;
          let filtedData = generateFilterFunc(
            item.eventMethods.filterMethod,
            data || {},
            res
          )();
          item.responseData = filtedData;
          item.props = handelResponseData(item.responseData, item);
        } catch (error) {
          ElMessage.error("接口数据获取失败：" + error);
        }
      }, item.request.pollingTime);
    } else if (item.request.ifInit && item.canReq) {
      try {
        let obj: any = {};
        // 判断是否使用数据源
        if (item.ifDataSource) {
          let real_Info: any = await getDataSourceDetail({
            id: item.dataSourceId,
          });
          if (real_Info.code == 200) {
            item.dataSourceInfo = real_Info.data;
            // console.log("item.dataSourceInfo ", item.dataSourceInfo);
          } else {
            ElMessage.error("数据源信息获取失败");
            return;
          }

          obj = await useDataSource(
            item.dataSourceInfo,
            JSON.parse(JSON.stringify(item.request))
          );
        } else {
          obj = JSON.parse(JSON.stringify(item.request));
        }
        let request = new Serves(obj.baseUrl).instance;
        if (obj.ifFormData) {
          let formdata = new FormData();
          for (let key in obj.data) {
            formdata.append(key, obj.data[key]);
          }
          obj.data = formdata;
        }
        const res = await request({
          ...obj,
        });
        const { data } = res;
        let filtedData = generateFilterFunc(
          item.eventMethods.filterMethod,
          data || {},
          res
        )();
        item.responseData = filtedData;
        item.props = handelResponseData(item.responseData, item);
      } catch (error) {
        ElMessage.error("接口数据获取失败：" + error);
      }
    }
  });
};

let computedStyle = computed(() => ({
  width: state.configsJson.width + "px",
  height: state.configsJson.height + "px",
  backgroundColor: state.configsJson.backgroundColor,
  backgroundImage: state.configsJson.showBgImg
    ? `url(${state.configsJson.backgroundImage})`
    : "",
  backgroundSize: "100% 100%",
  backgroundRepeat: "initial",
  backgroundAttachment: "initial",
  backgroundOrigin: "initial",
  backgroundClip: "initial",
}));
onBeforeUnmount(() => {
  Object.keys(timePolling).forEach((item) => {
    clearInterval(timePolling[item]);
  });

  // 移除键盘事件的监听
  document.removeEventListener("keydown", function (event) {});
});
</script>

<style scoped lang="scss">
/* HTML: <div class="loader"></div> */
.loader {
  width: 40px;
  height: 40px;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);

  --c: no-repeat linear-gradient(rgb(0, 102, 255) 0 0);
  background: var(--c), var(--c), var(--c), var(--c);
  background-size: 21px 21px;
  animation: l5 1.5s infinite cubic-bezier(0.3, 1, 0, 1);
}
@keyframes l5 {
  0% {
    background-position: 0 0, 100% 0, 100% 100%, 0 100%;
  }
  33% {
    background-position: 0 0, 100% 0, 100% 100%, 0 100%;
    width: 60px;
    height: 60px;
  }
  66% {
    background-position: 100% 0, 100% 100%, 0 100%, 0 0;
    width: 60px;
    height: 60px;
  }
  100% {
    background-position: 100% 0, 100% 100%, 0 100%, 0 0;
  }
}
</style>
